import nprogress from 'nprogress'
import qs from 'qs'
import type { App, Component, CSSProperties, InjectionKey, RenderFunction, VNode } from 'vue'
import Api from './Api.vue'
import { appConfig, initCfg } from './config/app';
import Empty from './Empty.vue'
import './types'
import { emitter } from './event'
import { Format, format } from './format'
import Http from './http'
import Login from './login'
import { Message, ModalReturnProps } from './modal';
import Rbac from './rbac'

import { installRouter } from './router'
import rv from './rv.vue'
import { clearExpireStorages } from './storage'


export * from './page/usePage'
export * from './modal'
export * from './hook'
export * from './config'
export * from './config/app'
export * from './rbac'
export * from './rbac/config'
export * from './format'
export * from './cache'
export * from './cookie'
export * from './server'
export * from './util'
export * from './router'
export * from './version'
export * from './login'
export * from './http'
export * from './event'
export * from './sys'

export const BEFORE_INITIAL = Symbol('beforeInitial')
export const INITIALIZED = Symbol('initialized')
export const PUSH = Symbol('push')
export const required = { required: true, message: '必填' }

export const login = new Login()
export const http = new Http()

const VuePlugin = {
  install: (app: App, options: any = {}): void => {
    app.use(Rbac)
    const prefix = options?.componentPrefix ?? ''
    app.component(prefix + Format.name, Format)
    app.component(prefix + Api.name, Api)
    app.config.globalProperties.$format = format
  },
}

export function initialized(app: App, callback: () => void, options?: any): void {
  clearExpireStorages()
  const initial = Symbol()
  emitter.on(BEFORE_INITIAL, (): void => {
    emitter.on(initial, async () => {
      login.init()
      http.init()
      installRouter(app)
      app.use(VuePlugin, options)
      await callback()
      setTimeout(() => emitter.emit(INITIALIZED, app), 300)
      appConfig.app.initCfg && initCfg()
    })
    emitter.emit(initial, app)
  })
  emitter.emit(BEFORE_INITIAL, app)
}

nprogress.configure({ showSpinner: false })

export function newError(content: string, type = 'error'): Error {
  const error = new Error(content)
  // @ts-ignore
  Message[type]({ content })
  return error
}

export {
  nprogress,
  rv,
  Format,
  qs,
  Api,
  Empty,
}

export type BaseType = string | number
export type Data = Record<string, any>
export type UnionType = BaseType | Data
export type RenderContent = string | RenderFunction
export type ClassName = string | Record<string, boolean> | (string | Record<string, boolean>)[]
export type FieldString<T> = {
  [K in keyof T]?: string
}
export type ComponentType = string | VNode | Component

export interface TreeNode {
  children?: TreeNode[]
  id: number
  pid: number
}

export interface IAppKey {
  appKey?: string | 'oauth'
}

// 保持原有的 PageIn 和 PageOut 定义
export interface PageIn {
  api?: <T extends Data>(pageIn: PageIn) => Promise<PageOut<T>> | PageOut<T>;
  hasTotal?: boolean;
  keyword?: string;
  pageNo?: number;
  pageSize?: number;
  params?: Data;
  sorts?: Array<string>; // 修改为 string 类型
}

export interface PageOut<T extends Data = Data> { // 确保 T 是 Data 的子类
  total: number;
  rows: T[];
}

export type ApiDataType = 'Page' | 'Array' | 'Object' | 'String' | 'Number' | 'Boolean';

export interface ApiContext {
  inject: boolean
  input: any
  loading: any
  onLoad: any,
  onOk: any,
  onSort: any,
  output: any,
  page: any,
  type: ApiDataType,
}

export const apiInjectionKey: InjectionKey<ApiContext> = Symbol('ApiContext')

export interface DialogProps {
  cancelable?: boolean
  cancelText?: string
  content: string
  okText?: string
  onCancel?: () => Promise<void> | void,
  onOk?: () => Promise<void> | void
  title?: string
  xClosable?: boolean
}

export interface IDialog {
  confirm: (props: DialogProps) => Promise<void>
  error: (props: DialogProps) => Promise<void>
  info: (props: DialogProps) => Promise<void>
  success: (props: DialogProps) => Promise<void>
  warn: (props: DialogProps) => Promise<void>
}

export interface IMessage {
  clear: any
  error: any
  info: any
  loading: any
  normal: any
  success: any
  warn: any
}

export interface MessageProps {
  content: any
  duration?: number
  onClose?: () => void
}

export interface INotification {
  clear: any
  close: any
  error: any
  info: any
  success: any
  warn: any
}

export interface NotificationProps {
  content: string
  duration?: number
  onClose?: () => void
  position: any
  title: string
}

export interface IModal extends ModalReturnProps {
  b: IModal,
  c: IModal,
  d: IModal,
  e: IModal,
}

export type ModalPosition = 'top' | 'bottom' | 'center' | 'left' | 'right'

export interface ModalProps {
  closable?: boolean
  close?: (isOk: boolean) => Promise<void | false> | void | false
  component: ComponentType
  contentClass?: ClassName
  contentStyle?: CSSProperties
  enableLock?: boolean
  escClosable?: boolean
  fullscreen?: boolean
  height?: BaseType,
  mask?: boolean,
  maskClass?: ClassName
  maskClosable?: boolean
  maskStyle?: CSSProperties
  modalClass?: ClassName
  modalStyle?: CSSProperties
  onClose?: (isOk: boolean, ...args: any) => void
  position?: ModalPosition
  props?: object
  title?: string
  top?: BaseType
  unmount?: boolean
  width?: BaseType
  xClosable?: boolean
}

export interface ModalState extends ModalProps {
  closing: boolean
  countdown: number
  defaultValue?: boolean
  lock: boolean
  modelValue: boolean
}

export interface IModalPicker extends Record<string, (input: Data, selectedKeys: BaseType[]) => Promise<[Data[], BaseType[]]>> {

}

export interface IFormat extends Record<string, (val: any, params?: any) => string> {
  IdNo: (val: string) => string
  Mobile: (val: string) => string
  BankAccount: (val: string) => string
  Boolean: (val: any) => string
  CnCurrency: (val: number) => string
  CnNumberUnit: (val: number) => string
  Currency: (val: number, precision?: number) => string
  Date: (val: any, pattern?: string) => string
  Datetime: (val: any) => string
  Decimal: (val: number, precision?: number) => string
  Integer: (val: number) => string
  Number: (val: number, precision?: number) => string
  Percent: (val: number) => string
  String: (val: any) => string
  Text: (val: any) => string
}

//region 枚举
export interface EnumProps {
  color?: string
  formatTitle?: string,
  key?: string
  title: string
  value: BaseType | boolean
}

export interface IEnum extends Record<string, () => Promise<EnumProps[]> | EnumProps[]> {
  Boolean: () => EnumProps[]
}

//endregion

//region 字典
export interface DictProps {
  data: Data
  formatName?: string,
  id?: BaseType
  name: string
  value: BaseType
}

export interface IDict extends Record<string, (params?: any) => Promise<DictProps[]> | DictProps[]> {
}

export const HTTPS_PREFIX = 'https://';
export const HTTP_PREFIX = 'http://';
//endregion
